package com.easypay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.easypay.bean.MicroAcqNotify;
import com.easypay.bean.TerminalInfo;
import com.easypay.util.HttpConnectUtils;
import com.easypay.util.RandomUtil;
import com.easypay.util.StringUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 *  微收单相关接口, 接口文档：https://doc.eycard.cn/web/#/42?page_id=543
 *  易生支付微信，支付宝，银联支付相关接口的实现示例
 *
 *
 * @date: 2021/10/24 11:02
 * @author: pandans
 */
public class MicroAcquiring {

    /**  微收单  */
    public static void main(String[] args) throws UnsupportedEncodingException {
        // 更新并获取签名密钥 -- 必调

      doGetSign();

        // 付款码（被扫）
//        doScanPay();

        // 主扫
        doNativePay();

        // 公众号服务窗
//        doJsPay();

        // 小程序支付  JSAPI
//        doMicroAppPay();

        // 银联行业码支付
//        doUnionPay();

        // 交易撤销
//        doCancel();

        // 查询
        //doQueryOrder("5310213320211027121532766533");
    }

    //    交易系统测试参数
//------------------------------------------------------------------------------------------------------------
//    请求地址:https://notify-test.eycard.cn:7443/WorthTech_Access_AppPaySystemV2/apppayacc
//            ------------------------------------------------------------------------------------------------------------
//    渠道编号: D01X66666666735
//    商户编号: 531000012971999
//    终端编号: W1489423
//    签名秘钥: sa72ivadl84273dlj2kdaia2idiadik5
//-----------------------------------------------------------------------------------------------------------
//    备注:
//    微信支付宝为真实交易,但是不会产生清算资金划拔，所以使用测试商家账号时请务必使用小于1元的小金额。
//    请务必在支付当日完成退款，否则因隔日退款失败造成的测试资金损失由测试机构自行承担，并视为放弃资金。
//
//            -----------------------------------------------------------------------------------------------------------
    //D01X66666666741,T,北京扫码付科技有限公司,EDferdssserrtXDe,dl250adsdda54sdaddakdlsdf7id3lfk


//    // 陕西环荣网络科技有限公司   服务商与特约商户关系上，该产品授权已被解除
////    // 渠道编号
//    public static final String CHANNELID = "D01X66666666730";
//    // 商户编号
//    public static final String MERID = "531000012971636";
//    // 终端编号
//    public static final String TERMID = "W1489324";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EDferdssserrtXDe";
//    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "sk77ivadl84273dlj8kdaia2idiadik2";

//    // 驻马店佳和医院有限公司   验证签名失败
//    // 渠道编号
//    public static final String CHANNELID = "D01X66666666750";
//    // 商户编号
//    public static final String MERID = "531000012972203";
//    // 终端编号
//    public static final String TERMID = "W1489466";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EDferdssserrtXDe";
//    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "sk77ivadl84273dlj8kdaia2idiadik2";


//    // 浙江迅翱信息科技有限公司3   无效商户
//    // 渠道编号
//    public static final String CHANNELID = "D01X66666666792";
//    // 商户编号
//    public static final String MERID = "531000012973446";
//    // 终端编号
//    public static final String TERMID = "W1489984";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EDferdssserrtXDe";
//    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "sk77ivadl84273dlj8kdaia2idiadik2";


//    // 浙江迅翱信息科技有限公司4   无效商户
//    // 渠道编号
//    public static final String CHANNELID = "D01X66666666793";
//    // 商户编号
//    public static final String MERID = "531000012973447";
//    // 终端编号
//    public static final String TERMID = "W1489985";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EDferdssserrtXDe";
//    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "sk77ivadl84273dlj8kdaia2idiadik2";
//

    //
//    // 渠道编号
//    public static final String CHANNELID = "D01X66666666782";
//    // 商户编号
//    public static final String MERID = "531000012972984";
//    // 终端编号
//    public static final String TERMID = "32773270";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EDferdssserrtXDe";
//    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "sa72ivadl84273dlj2kdaia2idiadik5";



////    // 渠道编号
//    public static final String CHANNELID = "D01X20200424011";
//    // 商户编号
//    public static final String MERID = "531000012973741";
//    // 终端编号
//    public static final String TERMID = "32774225";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EasyPayKwjiJinsy";
//    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "kaddddd4j578odd00il04fdl0d702vfd";


//    //259号文改造测试参数
    public static final String CHANNELID = "D01X20200424011";
    // 商户编号
    public static final String MERID = "531000012989458";
    // 终端编号
    public static final String TERMID = "32790065";
    // 渠道秘钥
    public static final String CHANNEL_KEY = "EasyPayKwjiJinsy";
    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
    public static String MER_SIGN_KEY = "52ol0jf2diid57skk2dda2fa4d2dkf8d";


//    // 临时    不行
//    // 渠道编号
//    public static final String CHANNELID = "D01X20200424011";
//    // 商户编号
//    public static final String MERID = "531000012972635";
//    // 终端编号
//    public static final String TERMID = "W1489663";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EasyPayKwjiJinsy";
//    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "kaddddd4j578odd00il04fdl0d702vfd";
//




//    // 北京扫码付科技有限公司
//    // 渠道编号
//    public static final String CHANNELID = "D01X66666666741";
//    // 商户编号
//    public static final String MERID = "531000012972133";
//    // 终端编号
//    public static final String TERMID = "W1489460";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EDferdssserrtXDe";
//    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "5dd1k8i8rdfssa5020kkf80rikddlrff";


//    // 山东秋文教育咨询有限公司
//    // 渠道编号
//    public static final String CHANNELID = "D01X20200424011";
//    // 商户编号
//    public static final String MERID = "531000012972635";
//    // 终端编号
//    public static final String TERMID = "W1489663";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EDferdssserrtXDe";
//


//
    // 浙江迅翱信息科技有限公司   胡登巍 配置的     报 无效商户
    // 渠道编号
//    public static final String CHANNELID = "D01X66666666794";
//    // 商户编号
//    public static final String MERID = "531000012973450";
//    // 终端编号
//    public static final String TERMID = "32773877";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EDferdssserrtXDe";
//    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "sa72ivadl84273dlj2kdaia2idiadik5";


//
    // 浙江迅翱信息科技有限公司    成功
    // 渠道编号
//    public static final String CHANNELID = "D01X00000801264";
//    // 商户编号
//    public static final String MERID = "531000012973385";
//    // 终端编号
//    public static final String TERMID = "32773796";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EDferdssserrtXDe";
//    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "3kddd3lvai1rf5if3k5d1dfaddjdddl5";



//    // 数科问题1
//    // 渠道编号
//    public static final String CHANNELID = "D01X20200424011";
//    // 商户编号
//    public static final String MERID = "531000012967751";
//    // 终端编号
//    public static final String TERMID = "32766936";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EasyPayKwjiJinsy";
//    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "kaddddd4j578odd00il04fdl0d702vfd";


//    // 浙江迅翱信息科技有限公司 新的    报 无效商户
//    // 渠道编号
//    public static final String CHANNELID = "D01X66666666791";
//    // 商户编号
//    public static final String MERID = "531000012973437";
//    // 终端编号
//    public static final String TERMID = "32773861";
//    // 渠道秘钥
//    public static final String CHANNEL_KEY = "EDferdssserrtXDe";
//    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "sk77ivadl84273dlj8kdaia2idiadik2";




    // 签名秘钥 -- 联调支持分配, 使用getSign接口更新
//    public static String MER_SIGN_KEY = "sk77ivadl84273dlj8kdaia2idiadik2";
//    public static String MER_SIGN_KEY = "o8daidall7dl35lad8dlavd4d0ddjjrr";

//    public static String MER_SIGN_KEY = "kaddddd4j578odd00il04fdl0d702vfd";

    /**
     * 接口测试地址 -- 联条支持提供
     */
//    public static final String BASE_URL = "https://notify-test.eycard.cn:7443/WorthTech_Access_AppPaySystemV2/apppayacc";


    public static final String BASE_URL = "https://mtest.eycard.cn/WorthTech_Access_AppPaySystemV2/apppayacc";

    /**
     * 此接口为必联调接口，根据“渠道秘钥”来获取签名密钥值；
     * 签名密钥值长期有效，获取一次后可一直有用，直至更新签名密钥值后旧密钥值失效；
     * 建议：为安全起见建议定期更新签名密钥值。
     *
     * 请求报文为：channelid=D01X66666666735&opt=getSign&sign=8E35ACD55C3E6CBEDACB9DD2C86067FC
     * ====> {"opt":"getSign","sign":"34F0173A5D7A771FC58874DCC7B22BC2","resultcode":"00","key":"ki1dkii2d7jfk3ldko1d3a2a8jaid35d","channelid":"D01X66666666735"}
     *
     */
    public static void doGetSign() {
        Map<String, String> request = new HashMap<>(2);
        request.put("channelid", CHANNELID);
        request.put("opt", "getSign");
        // 此处计算使用的是渠道密钥！！其他交易使用该接口获取的签名密钥
        calSignAndPut(request, CHANNEL_KEY);

        String response = doRequest(request);
        String key = JSONObject.parseObject(response).getString("key");
        if(checkSign(response, key)) {
            MER_SIGN_KEY = key;
        }

    }

    /**
     * 付款码支付（被扫支付）
     *
     * 此接口为付款码支付接口（消费者展示付款码进行支付）。
     * 适用于微信、支付宝、银联的付款码。
     *
     * 请求报文为：authcode=284385315658989158&termid=W1489460&tradeamt=1&opt=scanPay&tradetrace=5310213320211030053157655019&sign=7810E170F48AA05BD31ADF0997D95F5E&merid=531000012972133&body=%E6%B5%8B%E8%AF%95%E8%A2%AB%E6%89%AB%E6%94%AF%E4%BB%98&version=1&channelid=D01X66666666741
     * ====> {"wxtimeend":"20211030173159","wtorderid":"21420211030173158170886","sign":"9FE02FAF414D6681D93C9D66E2D015A6","acctype":"U","termid":"W1489460","opt":"scanPay","tradetrace":"5310213320211030053157655019","wxtransactionid":"2021103022001440875728051135","returnmsg":"Success","merid":"531000012972133","resultcode":"00","wxopenid":"2088102936140877","channelid":"D01X66666666741"}
     */
    public static void doScanPay() {
        Map<String, String> request = new HashMap<>(10);
        request.put("channelid", CHANNELID);
        request.put("merid", MERID);
        request.put("termid", TERMID);
        request.put("opt", "scanPay");
        // 商户订单号（控制在50位长度以内，确保在请求接口的系统中全局唯一；可以包含数字与字母；不能包含其他特殊字符）
        request.put("tradetrace", MERID.substring(0, 4) + MERID.substring(MERID.length() - 4) + StringUtils.getLocalDate() + RandomUtil.generateNumString(6));
        // 刷脸类型填写（faceScanPay）
        // request.put("maintradetype", "faceScanPay");
        // 交易金额，分
        request.put("tradeamt", "1");
        // 扫码支付授权码，设备读取用户微信、支付宝、银联钱包中的条码或者二维码信息

        request.put("authcode", "134543843828098150");
        // 商品或支付单简要描述
        request.put("body", "测试被扫支付");
        // 填写的值为2时，交易成功后返回优惠信息；针对单品营销的场景，填写的值为6
        // request.put("version", "");
        // 手续费（以分为单位,第一位是D或C，表示借、贷）
        // request.put("handingfee", "");

        //
        // request.put("identity", "JSON格式指定付款人信息，具体格式见附录");
        // request.put("instalment", "支付宝花呗分期");
        // request.put("patnersettleflag", "资金结算秒到标识，取值：1或者21：本次交易正常T1结算2：本次交易秒到（前提条件：代理需开通白名单、商户需要开通秒到功能）");
        // request.put("extparam", "JSON格式业务拓展参数，");
        // request.put("subappid", "微信子APPID，微信分配的子商户公众账号ID");
        // request.put("pnrinsidcd", "银联二维码专属字段：服务商机构标识码,银联分配的服务商机构标识码。");
        // request.put("acqaddndata", "银联二维码专属字段：收款方附加数据，详见附录说明");

        // 填写的值为2时，交易成功后返回优惠信息

        TerminalInfo terminalInfo = new TerminalInfo();
        terminalInfo.setLocation("+37.12/-121.213");
        String termInfo = JSON.toJSONString(terminalInfo).toLowerCase();
        request.put("terminalinfo", termInfo);

        request.put("version", "1");
        // 计算签名并设置签名
        calSignAndPut(request, MER_SIGN_KEY);
        // 接口请求
        String response = doRequest(request);
        // 验签
        checkSign(response, MER_SIGN_KEY);
    }

    /**
     * 主扫支付
     *
     * 仅支持 支付宝/银联/微信 主扫支付。
     * 商户生成动态付款码供消费者进行扫码付款。
     *
     * 银联测试请到：https://open.unionpay.com/tjweb/tool/qrcodeFormPage/mainSweepReceiverApp 平台测试
     */
    public static void doNativePay() {
        Map<String, String> request = new HashMap<>(10);
        request.put("channelid", CHANNELID);
        request.put("merid", MERID);
        request.put("termid", TERMID);
        // 操作类型（“apPreOrder”：支付宝；“wxPreOrder”: 微信； “upPreOrder”：银联），根据实际情况选其一
//        request.put("opt", "wxPreOrder");
        request.put("opt", "apPreOrder");

        if (request.get("opt") == "wxPreOrder") {
            // 填写的值为2时，交易成功后返回优惠信息；针对单品营销的场景，填写的值为6
            request.put("version", "5");  // 注意： 微信主扫时，version一定要设置为5，不然可能会报下单失败
        }

        request.put("tradetype", "NATIVE");
        // 商户订单号（控制在50位长度以内，确保在请求接口的系统中全局唯一；可以包含数字与字母；不能包含其他特殊字符）
        request.put("tradetrace", MERID.substring(0, 4) + MERID.substring(MERID.length() - 4) + StringUtils.getLocalDate() + RandomUtil.generateNumString(6));
        // 刷脸类型填写（faceScanPay）
        // request.put("maintradetype", "faceScanPay");
        // 交易金额，分
        request.put("tradeamt", "1");
        // 商品或支付单简要描述
        request.put("body", "测试被扫支付");
        // 客户端接收支付成功通知的地址，通知报文请见“后台通知接口”
        request.put("notifyurl", "https://notify-test.eycard.cn:7443/WorthTech_PayChannelModule_V1/Channel008/UnionPay_Weixin_Servlet");


        TerminalInfo terminalInfo = new TerminalInfo();
        terminalInfo.setLocation("+37.12/-121.213");
        String termInfo = JSON.toJSONString(terminalInfo);
        request.put("terminalinfo", termInfo);

//        //!!openid和subappid一对配置 支付宝（买家支付宝用户ID，参考文档 ），上送支付宝用户ID时，当前订单仅当前支付宝用户支付；微信（用户在商户 sub_appid 下的唯一标识，参考文档 ）
//        request.put("openid", "");
//        // 微信子APPID，微信分配的子商户公众账号ID
//        request.put("subappid", "");
        //

        // 手续费（以分为单位,第一位是D或C，表示借、贷）
        // request.put("handingfee", "");

        //
        // request.put("identity", "JSON格式指定付款人信息，具体格式见附录");
        // request.put("instalment", "支付宝花呗分期");
        // request.put("patnersettleflag", "资金结算秒到标识，取值：1或者21：本次交易正常T1结算2：本次交易秒到（前提条件：代理需开通白名单、商户需要开通秒到功能）");
        // request.put("extparam", "JSON格式业务拓展参数，");
        // request.put("subappid", "微信子APPID，微信分配的子商户公众账号ID");
        // request.put("pnrinsidcd", "银联二维码专属字段：服务商机构标识码,银联分配的服务商机构标识码。");
        // request.put("acqaddndata", "银联二维码专属字段：收款方附加数据，详见附录说明");


        // 计算签名并设置签名
        calSignAndPut(request, MER_SIGN_KEY);
        // 接口请求
        String response = doRequest(request);
        // 验签
        checkSign(response, MER_SIGN_KEY);
    }
    /**
     * 公众号/服务窗支付
     *
     * 支持微信公众号支付、支付宝服务窗/生活号支付
     */
    public static void doJsPay() {
        Map<String, String> request = new HashMap<>(10);
        request.put("channelid", CHANNELID);
        request.put("merid", MERID);
        request.put("termid", TERMID);
        // 操作类型（“apPreOrder”：支付宝；“wxPreOrder”: 微信； “upPreOrder”：银联），根据实际情况选其一
        request.put("opt", "wxPreOrder");
        request.put("tradetype", "JSAPI");
        // 商户订单号（控制在50位长度以内，确保在请求接口的系统中全局唯一；可以包含数字与字母；不能包含其他特殊字符）
        request.put("tradetrace", MERID.substring(0, 4) + MERID.substring(MERID.length() - 4) + StringUtils.getLocalDate() + RandomUtil.generateNumString(6));
//        request.put("tradetrace", "G2220222C00007404032");
        // 刷脸类型填写（faceScanPay）
        // request.put("maintradetype", "faceScanPay");
        // 交易金额，分
        request.put("tradeamt", "1");
        // 商品或支付单简要描述
        request.put("body", "行云支付");
        // 客户端接收支付成功通知的地址，通知报文请见“后台通知接口”
        request.put("notifyurl", "https://t.shunwei.info/api/pay/callback");

        //!!openid和subappid一对配置 支付宝（买家支付宝用户ID，参考文档 ），上送支付宝用户ID时，当前订单仅当前支付宝用户支付；微信（用户在商户 sub_appid 下的唯一标识，参考文档 ）

//        request.put("openid", "oIcV7w-8iHNq8ERvqikH1YiBxQe4");
        // 微信子APPID，微信分配的子商户公众账号ID
//        request.put("subappid", "wxde94a63529b9b709");

        request.put("openid", "oUpF8uO-kIpPRDvFevZCerLc-ipo"); //oVoLCwZzRVHwPrG3JvDs5Z_yc83s
////        // 微信子APPID，微信分配的子商户公众账号ID
        request.put("subappid", "wxee597080118d5c2d");
//        request.put("openid", "2088102936140877");
//        request.put("subappid", "2017122201079278");

        // 259号问改造专用
//        request.put("openid", "2088102936140877");
//        request.put("subappid", "2017122201079278");
        //
        // 填写的值为2时，交易成功后返回优惠信息；针对单品营销的场景，填写的值为6
        // request.put("version", "");
        // 手续费（以分为单位,第一位是D或C，表示借、贷）
        // request.put("handingfee", "");

        //
        // request.put("identity", "JSON格式指定付款人信息，具体格式见附录");
        // request.put("instalment", "支付宝花呗分期");
         request.put("patnersettleflag", "1");
        request.put("orgsmercode", "015440301563746");
        // request.put("extparam", "JSON格式业务拓展参数，");
        // request.put("pnrinsidcd", "银联二维码专属字段：服务商机构标识码,银联分配的服务商机构标识码。");
        // request.put("acqaddndata", "银联二维码专属字段：收款方附加数据，详见附录说明");


        request.put("version", "1");  // 填写的值为2时，交易成功后返回优惠信息

        TerminalInfo terminalInfo = new TerminalInfo();
//        terminalInfo.setLocation("+33.265831/+116.564248");
        terminalInfo.setTerminalIp("127.0.0.1");
        String termInfo = JSON.toJSONString(terminalInfo).toLowerCase();
        request.put("terminalinfo", termInfo);


        // 计算签名并设置签名
        calSignAndPut(request, MER_SIGN_KEY);
        request.put("termcretcode", "12345678");

        // 接口请求
        String response = doRequest(request);
        // 验签
        checkSign(response, MER_SIGN_KEY);
    }

    /**
     * 小程序支付预下单接口
     * 支持支付宝/微信小程序支付。
     * 支持外部APP 调用/唤起 支付宝/微信小程序 进行支付。
     */
    public static void doMicroAppPay() {
        Map<String, String> request = new HashMap<>(10);
        request.put("channelid", CHANNELID);
        request.put("merid", MERID);
        request.put("termid", TERMID);
        // 操作类型（“wxPreOrder”：微信；“apPreOrder”：支付宝），根据实际情况选其一
//        request.put("opt", "apPreOrder");
        request.put("opt", "wxPreOrder");
        request.put("tradetype", "JSAPI");
        // 商户订单号（控制在50位长度以内，确保在请求接口的系统中全局唯一；可以包含数字与字母；不能包含其他特殊字符）
        request.put("tradetrace", MERID.substring(0, 4) + MERID.substring(MERID.length() - 4) + StringUtils.getLocalDate() + RandomUtil.generateNumString(6));
        // 刷脸类型填写（faceScanPay）
        // request.put("maintradetype", "faceScanPay");
        // 交易金额，分
        request.put("tradeamt", "1");
        // 商品或支付单简要描述
        request.put("body", "电表充值0.01元");
        // 客户端接收支付成功通知的地址，通知报文请见“后台通知接口”
        request.put("notifyurl", "http://ess.com.cn:8068/Payment/BackNotification");


        //!!openid和subappid一对配置 支付宝（买家支付宝用户ID，参考文档 ），上送支付宝用户ID时，当前订单仅当前支付宝用户支付；微信（用户在商户 sub_appid 下的唯一标识，参考文档 ）
//        request.put("openid", "2088102936140877");
        request.put("openid", "oUpF8uO-kIpPRDvFevZCerLc-ipo");
        // 微信子APPID，微信分配的子商户公众账号I
//        request.put("subappid", "wx1b6403c1a6fd5a0d");


        TerminalInfo terminalInfo = new TerminalInfo();
        terminalInfo.setTerminalIp("192.168.5.131");
//        terminalInfo.setLocation("+37.12/-121.213");
        String termInfo = JSON.toJSONString(terminalInfo).toLowerCase();
        request.put("terminalinfo", termInfo);
        //
        // 填写的值为2时，交易成功后返回优惠信息；针对单品营销的场景，填写的值为6
        // request.put("version", "");
        // 手续费（以分为单位,第一位是D或C，表示借、贷）
        // request.put("handingfee", "");

        //
        // request.put("patnersettleflag", "资金结算秒到标识，取值：1或者21：本次交易正常T1结算2：本次交易秒到（前提条件：代理需开通白名单、商户需要开通秒到功能）");
        // request.put("extparam", "JSON格式业务拓展参数，");
        // 填写的值为2时，交易成功后返回优惠信息
        request.put("version", "1");
        // 计算签名并设置签名
        calSignAndPut(request, MER_SIGN_KEY);
        // 接口请求
        String response = doRequest(request);
        // 验签
        checkSign(response, MER_SIGN_KEY);
    }

    /**
     * 银联行业码支付
     *
     * 本接口仅适用于银联行业码交易，在商户网关自行与银联平台交互获得用户授权码后，再调用本接口进行预下单操作。
     *
     * !!测试使用仿真app测试
     */
    public static void doUnionPay() {
        Map<String, String> request = new HashMap<>(10);
        request.put("channelid", CHANNELID);
        request.put("merid", MERID);
        request.put("termid", TERMID);
        //  只有  “upPreOrder”：银联
        request.put("opt", "upPreOrder");
        request.put("tradetype", "JSAPI");
        // 商户订单号（控制在50位长度以内，确保在请求接口的系统中全局唯一；可以包含数字与字母；不能包含其他特殊字符）
        request.put("tradetrace", MERID.substring(0, 4) + MERID.substring(MERID.length() - 4) + StringUtils.getLocalDate() + RandomUtil.generateNumString(6));
        // 刷脸类型填写（faceScanPay）
        // request.put("maintradetype", "faceScanPay");
        // 交易金额，分
        request.put("tradeamt", "1");
        // 商品或支付单简要描述
        request.put("body", "测试银联jsapi支付");
        request.put("openid", "admin4");
        // 客户端接收支付成功通知的地址，通知报文请见“后台通知接口”
        request.put("notifyurl", "https://notify-test.eycard.cn:7443/WorthTech_PayChannelModule_V1/Channel008/UnionPay_Weixin_Servlet");
        // 此处需要通过银联认证的
        request.put("returnurl", "https://www.baidu.com");
        request.put("customerip", "127.0.0.1");
        //request.put("patnersettleflag", "1");
        //request.put("pnrinsidcd", "1");
        // 填写的值为2时，交易成功后返回优惠信息
        request.put("version", "1");
        // 计算签名并设置签名
        calSignAndPut(request, MER_SIGN_KEY);
        // 接口请求
        String response = doRequest(request);
        // 验签
//        checkSign(response, MER_SIGN_KEY);
    }


    /**
     * 交易查询
     * @param orderNo 交易订单号
     */
    public static void doQueryOrder(String orderNo) {
        Map<String, String> request = new HashMap<>(10);
        request.put("channelid", CHANNELID);
        request.put("merid", MERID);
        request.put("termid", TERMID);
        request.put("opt", "tradeQuery");
        request.put("tradetrace", orderNo);
        // 填写的值为2时，交易成功后返回优惠信息
        request.put("version", "1");
        // 计算签名并设置签名
        calSignAndPut(request, MER_SIGN_KEY);
        // 接口请求
        String response = doRequest(request);
        // 验签
        checkSign(response, MER_SIGN_KEY);
    }

    /**
     * @param notify 支付成功回调
     * @Description 支付成功回调， 请在服务端写相关接口接受 MicroAcquiring 参数， 并相应"ok"
     * @date: 2021/10/16 20:17
     * @author: pandans
     */
    public static JSONObject doNotify(MicroAcqNotify notify) {
        // 原交易流水号
        String tradetrace = notify.getTradetrace();
        // 自行根据交易流水号更i性能本地订单状态

        /**
         * 接受到报文后，请回复00，告诉易生服务器已接收到通知，
         * 如果核心平台收到第三方受理机构的应答不是成功或超时，核心平台认为通知失败，会约隔2^n(2^2，2^3…)重复通知8次，尽可能提高通知的成功率，但不保证通知最终能成功。
         */
        JSONObject result = new JSONObject();
        result.put("resultcode", "00");
        return result;
    }

    //
    /**
     * @Description 交易撤销 仅对当日交易可以撤销，日切时间为渠道服务器的00:00。
     * @date: 2021/10/16 20:17
     * @author: pandans
     */
    public static void doCancel() {
        Map<String, String> request = new HashMap<>(10);
        request.put("channelid", CHANNELID);
        request.put("merid", MERID);
        request.put("termid", TERMID);
        request.put("opt", "cancel");
        request.put("tradetrace", MERID.substring(0, 4) + MERID.substring(MERID.length() - 4) + StringUtils.getLocalDate() + RandomUtil.generateNumString(6));
        // 	原交易流水； 与oriwtorderid字段可以二选一上送，如果都上送，以本节点为准。 商户上送的tradetrace
        request.put("oritradetrace", "5310213320211030053157655019");
        // 原交易流水； 与oriwtorderid字段可以二选一上送，如果都上送，以本节点为准。 支付时返回的wtorderid
        request.put("oriwtorderid", "21420211030173158170886");
        // 填写的值为2时，交易成功后返回优惠信息
        request.put("version", "1");
        // 计算签名并设置签名
        calSignAndPut(request, MER_SIGN_KEY);
        // 接口请求
        String response = doRequest(request);
        // 验签
        checkSign(response, MER_SIGN_KEY);
    }

    /**
     * @param request: 请求参数, 不包含sign
     * @Description 公用请求串
     * @date: 2021/10/24 11:29
     * @author: pandans
     */
    public static String doRequest(Map<String, String> request) {
        try {
            System.out.println("请求报文："+ JSON.toJSONString(request));
            String response = HttpConnectUtils.sendHttpSRequest( BASE_URL, request, "POST", null);
            System.out.println("响应报文：" + response);
            return response;

        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 根据返回的内容计算签名
     * @param response 服务器返回报文
     * @param signKey 签名KEY
     * @return
     */
    public static boolean checkSign(String response, String signKey) {
        Map<String, String> signMap = JSONObject.parseObject(response, Map.class);
        // 报文返回的签名
        String sign = signMap.get("sign");
        // 报文计算的签名
        String calSign = calSign(signMap, signKey);
        boolean res = sign.equals(calSign);
        System.out.println("验证签名====》" + res);
        return res;
    }
    /**
     * 计算sign, 将sign 写入Map中
     * @param request 请求内容不包含sign
     * @param signKey 签名key
     */
    public static void calSignAndPut(Map<String, String> request, String signKey) {
        String md5 = calSign(request, signKey);
        request.put("sign", md5);
    }
    /**
     * 计算sign
     * @param request 请求内容不包含sign
     * @param signKey 签名key
     */
    public static String calSign(Map<String, String> request, String signKey) {
        Set<String> keySet = request.keySet();
        TreeSet<String> treeSet = new TreeSet<>(keySet);
        StringBuilder stringBuilder = new StringBuilder();
        for(String key : treeSet) {
            if(!"sign".equals(key) && !StringUtils.isEmpty(request.get(key))) {
                stringBuilder.append(key).append("=").append(request.get(key)).append("&");
            }
        }
        stringBuilder.append("key=").append(signKey);
        String str = stringBuilder.toString();
        System.out.println(str);
        String md5 = calMD5(str);
        return md5;
    }

    /**
     * MD5 算法
     * @param data 待计算源数据
     * @return md5值
     */
    public static String calMD5(String data) {
        // 使用springboot 请使用如下注释方法，兼容性更高
        // DigestUtils.md5DigestAsHex(data.getBytes(StandardCharsets.UTF_8)).toUpperCase();
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(data.getBytes(StandardCharsets.UTF_8));
            byte[] s = md.digest();
            StringBuilder result = new StringBuilder();
            for (byte b : s) {
                result.append(Integer.toHexString((0x000000FF & b) | 0xFFFFFF00).substring(6));
            }
            return result.toString().toUpperCase();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }


}
